package com.corewillsoft.fireflies.ui;

import java.util.Arrays;
import java.util.List;

import javax.microedition.khronos.opengles.GL10;

import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.background.AutoParallaxBackground;
import org.anddev.andengine.entity.scene.background.ParallaxBackground.ParallaxEntity;
import org.anddev.andengine.entity.scene.menu.MenuScene;
import org.anddev.andengine.entity.scene.menu.MenuScene.IOnMenuItemClickListener;
import org.anddev.andengine.entity.scene.menu.item.IMenuItem;
import org.anddev.andengine.entity.scene.menu.item.TextMenuItem;
import org.anddev.andengine.entity.scene.menu.item.decorator.ColorMenuItemDecorator;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.ActivityUtils;

import android.content.Intent;
import android.graphics.Color;
import android.view.KeyEvent;

import com.corewillsoft.fireflies.R;
import com.corewillsoft.fireflies.engine.IConstants;
import com.corewillsoft.fireflies.engine.LevelResult;
import com.corewillsoft.fireflies.sounds.SoundsManager;
import com.corewillsoft.fireflies.util.ScreenUtils;

public abstract class BaseActivity extends BaseGameActivity implements IOnMenuItemClickListener, IConstants {
	
	protected Scene scene;
	protected Camera camera;
	// protected Engine engine;

	private int menuOpened;

	private MenuScene menuScene;
	private Font itemFont;
	private Font titleFont;
	private Font subtitleFont;

	private BitmapTextureAtlas bitmapTextureAtlas;
	private BitmapTextureAtlas autoParallaxBackgroundTexture;
	private TextureRegion parallaxLayerBack;
	private TextureRegion parallaxLayerMid;
	private TextureRegion parallaxLayerFront;
	private OnMenuClickedListener onMenuClickListener;

	public static enum MENU {
		CONTINUE(R.string.CONTINUE),
		CANCEL(R.string.CANCEL),
		QUIT(R.string.quit),
		RESTART(R.string.restart),
		SETTINGS(R.string.settings),
		MAP(R.string.map),
		NEXT_LEVEL(R.string.next_level),
		EDITOR(R.string.editor),
		SAVE(R.string.save),
		RESTORE(R.string.restore),
		GAME(R.string.game),
		NEW_GAME(R.string.new_game),
		ACHIEVEMENTS(R.string.achievements),
		EXIT_GAME(R.string.exit_game);

		private final int name;

		private MENU(int name) {
			this.name = name;
		}

		public int getName() {
			return name;
		}
	}

	private static final List<MENU> mainMenu = Arrays.asList(
			MENU.GAME,
			MENU.ACHIEVEMENTS,
			MENU.EXIT_GAME
			);

	private static final List<MENU> mapMenu = Arrays.asList(
			MENU.CONTINUE,
			MENU.NEW_GAME,
			MENU.CANCEL
			);

	private static final List<MENU> commonGameMenu = Arrays.asList(
			MENU.CONTINUE,
			MENU.RESTART,
			MENU.MAP,
			MENU.QUIT
			);
	private static final List<MENU> failedResultMenu = Arrays.asList(
			MENU.RESTART,
			MENU.MAP,
			MENU.QUIT
			);

	private static final List<MENU> successResultMenu = Arrays.asList(
			MENU.NEXT_LEVEL,
			MENU.RESTART,
			MENU.MAP,
			MENU.QUIT
			);

	private static final List<MENU> gameFinishedMenu = Arrays.asList(
			MENU.RESTART,
			MENU.MAP,
			MENU.QUIT
			);

	@Override
	public void onLoadResources() {
		initAssetsPath();
		
		SoundsManager.getInstance().initSounds();
		
		this.bitmapTextureAtlas = new BitmapTextureAtlas(64, 64, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		getEngine().getTextureManager().loadTexture(this.bitmapTextureAtlas);

		// Load font for Menu
		initFonts();

		this.bitmapTextureAtlas = new BitmapTextureAtlas(256, 128, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.autoParallaxBackgroundTexture = new BitmapTextureAtlas(1024, 1024, TextureOptions.DEFAULT);
		this.parallaxLayerFront = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
				this.autoParallaxBackgroundTexture, this, "parallax_background_layer_front.png", 0, 0);
		this.parallaxLayerBack = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
				this.autoParallaxBackgroundTexture, this, "parallax_background_layer_back.png", 0, 188);
		this.parallaxLayerMid = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
				this.autoParallaxBackgroundTexture, this, "parallax_background_layer_mid.png", 0, 669);
		getEngine().getTextureManager().loadTextures(this.bitmapTextureAtlas, this.autoParallaxBackgroundTexture);
	}

	@Override
	public Scene onLoadScene() {
		getEngine().registerUpdateHandler(new FPSLogger());
		scene = new Scene();
		final AutoParallaxBackground autoParallaxBackground = new AutoParallaxBackground(0, 0, 0, 5);
		autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(0.0f, new Sprite(0, ScreenUtils.getInstance()
				.getRelativeHeight() - this.parallaxLayerBack.getHeight(), this.parallaxLayerBack)));
		autoParallaxBackground
				.attachParallaxEntity(new ParallaxEntity(-5.0f, new Sprite(0, 80, this.parallaxLayerMid)));
		autoParallaxBackground.attachParallaxEntity(new ParallaxEntity(-10.0f, new Sprite(0, ScreenUtils.getInstance()
				.getRelativeHeight() - this.parallaxLayerFront.getHeight(), this.parallaxLayerFront)));
		scene.setBackground(autoParallaxBackground);

		return scene;
	}

	private void initFonts() {

		BitmapTextureAtlas itemTexture = new BitmapTextureAtlas(256, 256,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		getEngine().getTextureManager().loadTexture(itemTexture);

		this.itemFont = FontFactory.createFromAsset(itemTexture, this,
				"Plok.ttf", 32, true, Color.WHITE);
		getEngine().getFontManager().loadFont(this.itemFont);

		BitmapTextureAtlas titleTexture = new BitmapTextureAtlas(512, 512,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		getEngine().getTextureManager().loadTexture(titleTexture);

		this.titleFont = FontFactory.createFromAsset(titleTexture, this,
				"Plok.ttf", 42, true, Color.WHITE);
		getEngine().getFontManager().loadFont(this.titleFont);

		BitmapTextureAtlas subtitleTexture = new BitmapTextureAtlas(512, 512,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		getEngine().getTextureManager().loadTexture(subtitleTexture);

		this.subtitleFont = FontFactory.createFromAsset(subtitleTexture, this,
				"Plok.ttf", 22, true, Color.WHITE);
		getEngine().getFontManager().loadFont(this.subtitleFont);
	}

	@Override
	public Engine onLoadEngine() {
		float relativeWidth = ScreenUtils.getInstance().getRelativeWidth();
		float relativeHeight = ScreenUtils.getInstance().getRelativeHeight();

		this.camera = new Camera(0, 0, relativeWidth, relativeHeight);
		EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.PORTRAIT,
				new RatioResolutionPolicy(relativeWidth, relativeHeight), this.camera);
		ActivityUtils.requestFullscreen(this);

		engineOptions.setNeedsSound(true);
		engineOptions.setNeedsMusic(true);
		Engine engine = new Engine(engineOptions);
		SoundsManager.initInstance(engine, this);

		return engine;
	}

	/**
	 * show Main Menu
	 * @param listener
	 */
	protected void showMainMenu(OnMenuClickedListener listener) {
		setOnMenuClickListener(listener);

		menuScene = new MenuScene(camera, this);

		menuScene.addMenuItem(getMenuTitle(-1, getString(R.string.main_menu)));
		menuScene.addMenuItem(getMenuMargin());

		// update items
		updateItems(mainMenu);
		scene.setChildScene(menuScene, false, true, true);
	}

	/**
	 * show Map Menu
	 * @param listener
	 */
	protected void showMapMenu(OnMenuClickedListener listener) {
		setOnMenuClickListener(listener);
		pushMenu();

		menuScene = new MenuScene(camera, this);

		menuScene.addMenuItem(getMenuTitle(-1, getString(R.string.menu)));
		menuScene.addMenuItem(getMenuMargin());

		// update items
		updateItems(mapMenu);
		scene.setChildScene(menuScene, false, true, true);
	}

	protected void showGameMenu(OnMenuClickedListener listener) {
		setOnMenuClickListener(listener);
		pushMenu();

		menuScene = new MenuScene(camera, this);

		menuScene.addMenuItem(getMenuTitle(-1, getString(R.string.menu)));
		menuScene.addMenuItem(getMenuMargin());

		// update items
		updateItems(commonGameMenu);
		scene.setChildScene(menuScene, false, true, true);
	}

	/**
	 * shows menu after level failed
	 * @param levelResult
	 */
	protected void showResultMenu(LevelResult levelResult, OnMenuClickedListener listener) {
		setOnMenuClickListener(listener);

		menuScene = new MenuScene(camera, this);

		// add title
		menuScene.addMenuItem(getMenuTitle(-1, getString(levelResult.getDialogTitleId())));
		menuScene.addMenuItem(getMenuSubtitle(-1, getString(levelResult.getDialogSubtitleId())));
		menuScene.addMenuItem(getMenuMargin());

		// add items
		if (LevelResult.WON.equals(levelResult)) {
			updateItems(successResultMenu);
		} else if (LevelResult.LOST.equals(levelResult)) {
			updateItems(failedResultMenu);
		} else if (LevelResult.GAME_FINISHED.equals(levelResult)) {
			updateItems(gameFinishedMenu);
		}
		scene.setChildScene(menuScene, false, true, true);
	}

	private void updateItems(List<MENU> menuList) {
		for (MENU menu : menuList) {
			menuScene.addMenuItem(getMenuItem(menu.ordinal(), getString(menu.getName())));
		}
		menuScene.buildAnimations();
		menuScene.setBackgroundEnabled(false);
	}

	private IMenuItem getMenuTitle(int id, String title) {
		TextMenuItem menuItem = new TextMenuItem(id, titleFont, title);
		IMenuItem decoratedMenuItem = new ColorMenuItemDecorator(menuItem, 1, 0, 0, 1, 0, 0);
		decoratedMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		return decoratedMenuItem;
	}

	private IMenuItem getMenuSubtitle(int id, String title) {
		TextMenuItem menuItem = new TextMenuItem(id, subtitleFont, title);
		IMenuItem decoratedMenuItem = new ColorMenuItemDecorator(menuItem, 0, 0, 1, 0, 0, 1);
		decoratedMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		return decoratedMenuItem;
	}

	private IMenuItem getMenuItem(int id, String title) {
		TextMenuItem menuItem = new TextMenuItem(id, itemFont, title);
		IMenuItem decoratedMenuItem = new ColorMenuItemDecorator(menuItem, 1, 0, 0, 0, 0, 0);
		decoratedMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		return decoratedMenuItem;
	}

	private IMenuItem getMenuMargin() {
		TextMenuItem menuItem = new TextMenuItem(-1, itemFont, "");
		IMenuItem decoratedMenuItem = new ColorMenuItemDecorator(menuItem,
				1, 0, 0, 0, 0, 0);
		decoratedMenuItem.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		return decoratedMenuItem;
	}

	@Override
	public boolean onMenuItemClicked(MenuScene pMenuScene, IMenuItem pMenuItem,
			float pMenuItemLocalX, float pMenuItemLocalY) {
		
//		pMenuItem.setColor(235f, 0f, 0f);
		if (pMenuItem.getID() < 0) {
			return false;
		}

		SoundsManager.getInstance().playMenuClick();

		MENU menuType = MENU.values()[pMenuItem.getID()];
		processMenuTypeClick(menuType);
		switch (menuType) {
		case NEXT_LEVEL:
			popMenu();
			return true;
		case CONTINUE:
			popMenu();
			resumeGame();
			return true;
		case QUIT:
			popMenu();
			return true;
		case MAP:
			popMenu();
			return true;
		case SETTINGS:
			return true;
		case RESTART:
			popMenu();
			resumeGame();
			return true;
		case SAVE:
			popMenu();
			resumeGame();
			return true;
		case RESTORE:
			popMenu();
			resumeGame();
			return true;
		case CANCEL:
			popMenu();
			return true;
		case NEW_GAME:
			popMenu();
			return true;
		default:
			return false;
		}
	}

	private void processMenuTypeClick(MENU menuType) {
		if ((onMenuClickListener != null) && (!onMenuClickListener.onMenuClicked(menuType))) {
			processDefaultClick(menuType);
		}
	}

	private void processDefaultClick(MENU menuType) {
		switch (menuType) {
		case NEXT_LEVEL:
			break;
		case CONTINUE:
			break;
		case QUIT:
			finish();
			Intent intent = new Intent(this, MainMenuActivity.class);
			intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			intent.putExtra("from_game_activity", true);
			startActivity(intent);
			break;
		case MAP:
			finish();
			break;
		case SETTINGS:
			break;
		case RESTART:
			break;
		case SAVE:
			break;
		case RESTORE:
			break;
		}
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if ((event.getAction() == KeyEvent.ACTION_DOWN)) {
			if (keyCode == KeyEvent.KEYCODE_BACK) {
				onHardKeyBackPressed();
				if (isMenuOpened()) {
					popMenu();
					resumeGame();
				} else {
					finish();
				}
				return true;
			} else if ((keyCode == KeyEvent.KEYCODE_MENU) && !isMenuOpened()) {
				pauseGame();
				onHardKeyMenuPressed();
				return true;
			}
		}
		return super.onKeyDown(keyCode, event);
	}

	private boolean isMenuOpened() {
		return (menuOpened > 0);
	}

	private void popMenu() {
		menuOpened--;
		menuScene.back();
	}

	private void pushMenu() {
		menuOpened++;
	}

	abstract protected void pauseGame();

	abstract protected void resumeGame();

	abstract protected void onHardKeyMenuPressed();

	public void onHardKeyBackPressed() {
	}

	protected void setOnMenuClickListener(OnMenuClickedListener listener) {
		onMenuClickListener = listener;
	}

	protected interface OnMenuClickedListener {

		/**
		 * @param type
		 *            type of menu
		 * @return @true if action was successfuly processed, @false otherwise.
		 */
		boolean onMenuClicked(MENU type);
	}

	private void initAssetsPath() {
		SoundFactory.setAssetBasePath(SOUNDS_PATH);
		MusicFactory.setAssetBasePath(SOUNDS_PATH);
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath(TEXTURE_PATH);
		FontFactory.setAssetBasePath(FONT_PATH);
	}
}
